package com.uinnova.product.eam.service.impl;

import cn.hutool.core.lang.Assert;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.model.es.CiClassLimitUse;
import com.uinnova.product.eam.model.vo.CiClassLimitUseDetail;
import com.uinnova.product.eam.model.vo.CiClassLimitUseSaveReq;
import com.uinnova.product.eam.model.vo.RelateClassInfo;
import com.uinnova.product.eam.service.CiClassLimitUseSvc;
import com.uinnova.product.eam.service.es.CiClassLimitUseDao;
import com.uinnova.product.vmdb.comm.model.ci.CCcCiClass;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uino.api.client.cmdb.ICIClassApiSvc;
import com.uino.bean.cmdb.enums.AttrNameKeyEnum;
import com.uino.dao.util.ESUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Log4j2
public class CiClassLimitUseSvcImpl implements CiClassLimitUseSvc {

    @Autowired
    private CiClassLimitUseDao ciClassLimitUseDao;
    @Autowired
    private ICIClassApiSvc classSvc;

    @Override
    public List<RelateClassInfo> relateClasses(String ciClassCode) {
        //获取分类定义
        CCcCiClass cdt = new CCcCiClass();
        cdt.setClassCodeEqual(ciClassCode);
        List<CcCiClassInfo> classInfos = classSvc.queryClassByCdt(cdt);
        if (CollectionUtils.isEmpty(classInfos)) {
            throw new BinaryException("分类不存在：" + ciClassCode);
        }
        CcCiClassInfo ciClassInfo = classInfos.get(0);
        if (CollectionUtils.isEmpty(ciClassInfo.getAttrDefs())) {
            return new ArrayList<>();
        }
        //"所属资产"属性关联分类ids
        List<Long> relateCiClassIds = new ArrayList<>();
        for (CcCiAttrDef ccCiAttrDef : ciClassInfo.getAttrDefs()) {
            if (ccCiAttrDef.getProType() == null
                    || ccCiAttrDef.getProType() != AttrNameKeyEnum.EXTERNAL_ASSET.getType()
                    || StringUtils.isBlank(ccCiAttrDef.getProDropSourceDef())) {
                continue;
            }
            try {
                Long relateCiClassId = Long.parseLong(ccCiAttrDef.getProDropSourceDef());
                if (!relateCiClassIds.contains(relateCiClassId)) {
                    relateCiClassIds.add(relateCiClassId);
                }
            } catch (Exception e) {
                log.error("所属资产：关联属性约束类型转换异常{}", ccCiAttrDef.getProDropSourceDef());
            }
        }
        if (CollectionUtils.isEmpty(relateCiClassIds)) {
            return new ArrayList<>();
        }
        //"所属资产"属性关联分类列表
        CCcCiClass relateCdt = new CCcCiClass();
        relateCdt.setIds(relateCiClassIds.toArray(new Long[relateCiClassIds.size()]));
        List<CcCiClassInfo> relateClassInfos = classSvc.queryClassByCdt(relateCdt);
        if (CollectionUtils.isEmpty(relateClassInfos)) {
            return new ArrayList<>();
        }
        Map<Long, CcCiClass> relateClassMap = relateClassInfos.stream()
                .map(CcCiClassInfo::getCiClass)
                .collect(Collectors.toMap(CcCiClass::getId, Function.identity(), (k1,k2) -> k1));
        List<RelateClassInfo> results = new ArrayList<>();
        for (Long relateCiClassId : relateCiClassIds) {
            if (!relateClassMap.containsKey(relateCiClassId)) {
                continue;
            }
            CcCiClass ciClass = relateClassMap.get(relateCiClassId);
            results.add(new RelateClassInfo(ciClass.getClassName(), ciClass.getClassCode()));
        }
        return results;
    }

    @Override
    public void save(CiClassLimitUseSaveReq req) {
        Assert.notNull(req, "分类code不能为空");
        Assert.notNull(req.getCiClassCode(), "分类code不能为空");
        Assert.notNull(req.getLimitUse(), "是否限制引用不能为空");
        CiClassLimitUse ciClassLimitUse = new CiClassLimitUse();
        ciClassLimitUse.setCiClassCode(req.getCiClassCode());
        ciClassLimitUse.setLimitUse(req.getLimitUse());
        if (req.getLimitUse()) {
            Assert.notNull(req.getAttrId(), "限制引用属性id不能为空");
            checkLimitUse(req.getCiClassCode(), req.getAttrId());
            ciClassLimitUse.setAttrId(req.getAttrId());
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ciClassCode.keyword", req.getCiClassCode()));
        ciClassLimitUseDao.deleteByQuery(query, true);

        ciClassLimitUse.setId(ESUtil.getUUID());
        ciClassLimitUse.setCreator(SysUtil.getCurrentUserInfo().getLoginCode());
        ciClassLimitUse.setCreateTime(ESUtil.getNumberDateTime());
        ciClassLimitUse.setModifier(SysUtil.getCurrentUserInfo().getLoginCode());
        ciClassLimitUse.setModifyTime(ESUtil.getNumberDateTime());
        ciClassLimitUseDao.saveOrUpdate(ciClassLimitUse);
    }

    public Map<String, CcCiClassInfo> checkLimitUse(String ciClassCode, Long attrId) {
        if (BinaryUtils.isEmpty(ciClassCode)) {
            throw new BinaryException("ciClassCode不可为空！");
        }
        if (BinaryUtils.isEmpty(attrId)) {
            throw new BinaryException("属性id不可为空！");
        }
        Map<String, CcCiClassInfo> result = new HashMap<>();
        //获取分类定义
        CCcCiClass cdt = new CCcCiClass();
        cdt.setClassCodeEqual(ciClassCode);
        List<CcCiClassInfo> classInfos = classSvc.queryClassByCdt(cdt);
        if (CollectionUtils.isEmpty(classInfos)) {
            throw new BinaryException("分类不存在：" + ciClassCode);
        }
        CcCiClassInfo ciClassInfo = classInfos.get(0);
        if (CollectionUtils.isEmpty(ciClassInfo.getAttrDefs())) {
            throw new BinaryException("该分类属性列表为空：" + ciClassCode);
        }
        List<CcCiAttrDef> attrDefs = ciClassInfo.getAttrDefs().stream().filter(each -> attrId.equals(each.getId())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(attrDefs)) {
            throw new BinaryException("属性不存在：" + attrId);
        }
        CcCiAttrDef attrDef = attrDefs.get(0);
        if (attrDef.getProType() == null || attrDef.getProType() != AttrNameKeyEnum.EXTERNAL_ASSET.getType()) {
            throw new BinaryException("所选引用属性不是“所属资产”类型");
        }
        if (StringUtils.isBlank(attrDef.getProDropSourceDef())) {
            throw new BinaryException("所选引用属性“约束”分类为空");
        }
        Long relateCiClassId;
        try {
            relateCiClassId = Long.parseLong(attrDef.getProDropSourceDef());
        } catch (Exception e) {
            log.error("所属资产：关联属性约束类型转换异常{}", attrDef.getProDropSourceDef());
            throw new BinaryException("所属资产：关联属性约束类型转换异常" + attrDef.getProDropSourceDef());
        }
        //"所属资产"属性关联分类列表
        CCcCiClass relateCdt = new CCcCiClass();
        relateCdt.setId(relateCiClassId);
        List<CcCiClassInfo> relateClassInfos = classSvc.queryClassByCdt(relateCdt);
        if (CollectionUtils.isEmpty(relateClassInfos)) {
            throw new BinaryException("“所属资产”分类不存在");
        }
        CcCiClassInfo relateClassInfo = relateClassInfos.get(0);

        result.put("ciClassInfo", ciClassInfo);
        result.put("relateClassInfo", relateClassInfo);

        return result;
    }

    @Override
    public CiClassLimitUseDetail detail(String ciClassCode) {
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("ciClassCode.keyword", ciClassCode));
        List<CiClassLimitUse> ciClassLimitUses = ciClassLimitUseDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(ciClassLimitUses)) {
            CiClassLimitUseDetail ciClassLimitUseDetail = new CiClassLimitUseDetail();
            ciClassLimitUseDetail.setCiClassCode(ciClassCode);
            ciClassLimitUseDetail.setLimitUse(false);
            return ciClassLimitUseDetail;
        }
        CiClassLimitUse ciClassLimitUse = ciClassLimitUses.get(0);
        if (!ciClassLimitUse.getLimitUse()) {
            return EamUtil.copy(ciClassLimitUse, CiClassLimitUseDetail.class);
        }
        Map<String, CcCiClassInfo> ccCiClassInfoMap;
        try {
            ccCiClassInfoMap = checkLimitUse(ciClassLimitUse.getCiClassCode(), ciClassLimitUse.getAttrId());
        } catch (Exception exception) {
            log.error(exception.getMessage());
            log.error("{}获取关联属性/关联属性分类异常,资产引用关闭", ciClassCode);
            ciClassLimitUse.setLimitUse(false);
            ciClassLimitUse.setAttrId(null);
            return EamUtil.copy(ciClassLimitUse, CiClassLimitUseDetail.class);
        }
        CiClassLimitUseDetail detail = EamUtil.copy(ciClassLimitUse, CiClassLimitUseDetail.class);
        CcCiClassInfo relateClass = ccCiClassInfoMap.get("relateClassInfo");
        if (!BinaryUtils.isEmpty(relateClass)) {
            detail.setRelateClassId(relateClass.getCiClass().getId());
            detail.setRelateClassCode(relateClass.getCiClass().getClassCode());
            detail.setRelateClassName(relateClass.getCiClass().getClassName());
        } else {
            log.error("{}获取关联属性/关联属性分类为空,资产引用关闭", ciClassCode);
            ciClassLimitUse.setLimitUse(false);
            ciClassLimitUse.setAttrId(null);
            return EamUtil.copy(ciClassLimitUse, CiClassLimitUseDetail.class);
        }
        return detail;
    }

    @Override
    public List<CiClassLimitUseDetail> details(Set<Long> ciClassIds) {
        if (CollectionUtils.isEmpty(ciClassIds)) {
            return new ArrayList<>();
        }
        CCcCiClass cdt = new CCcCiClass();
        cdt.setIds(ciClassIds.toArray(new Long[ciClassIds.size()]));
        List<CcCiClassInfo> ciClasses = classSvc.queryClassByCdt(cdt);
        if (CollectionUtils.isEmpty(ciClasses)) {
           return new ArrayList<>();
        }
        Map<String, CcCiClassInfo> ciClassInfoMap = new HashMap<>();
        for (CcCiClassInfo ciClassInfo : ciClasses) {
            CcCiClass ciClass = ciClassInfo.getCiClass();
            if (ciClass == null || ciClass.getId() == null || StringUtils.isBlank(ciClass.getClassCode())) {
                continue;
            }
            ciClassInfoMap.put(ciClass.getClassCode(), ciClassInfo);
        }
        if (CollectionUtils.isEmpty(ciClassInfoMap)) {
            return new ArrayList<>();
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termsQuery("ciClassCode.keyword", ciClassInfoMap.keySet()));
        List<CiClassLimitUse> ciClassLimitUses = ciClassLimitUseDao.getListByQuery(query);
        if (CollectionUtils.isEmpty(ciClassLimitUses)) {
            return new ArrayList<>();
        }

        List<CiClassLimitUseDetail> details = new ArrayList<>();
        for (CiClassLimitUse ciClassLimitUse : ciClassLimitUses) {
            CiClassLimitUseDetail detail = EamUtil.copy(ciClassLimitUse, CiClassLimitUseDetail.class);
            if (!detail.getLimitUse()) {
                continue;
            }
            if (BinaryUtils.isEmpty(detail.getAttrId())) {
                continue;
            }
            if (!ciClassInfoMap.containsKey(detail.getCiClassCode())) {
                continue;
            }
            CcCiClassInfo ciClassInfo = ciClassInfoMap.get(detail.getCiClassCode());
            detail.setCiClassId(ciClassInfo.getCiClass().getId());
            Map<String, CcCiClassInfo> ccCiClassInfoMap;
            try {
                ccCiClassInfoMap = checkLimitUse(ciClassLimitUse.getCiClassCode(), ciClassLimitUse.getAttrId());
            } catch (Exception exception) {
                log.error(exception.getMessage());
                log.error("{}获取关联属性/关联属性分类异常,资产引用关闭", ciClassLimitUse.getCiClassCode());
                continue;
            }
            CcCiClassInfo relateClass = ccCiClassInfoMap.get("relateClassInfo");
            if (BinaryUtils.isEmpty(relateClass)) {
                continue;
            }
            detail.setRelateClassId(relateClass.getCiClass().getId());
            detail.setRelateClassCode(relateClass.getCiClass().getClassCode());
            detail.setRelateClassName(relateClass.getCiClass().getClassName());
            detail.setLimitAttrDefs(getLimitAttrDefsByAttrId(ciClassInfo, detail.getAttrId()));

            details.add(detail);
        }
        return details;
    }

    private List<CcCiAttrDef> getLimitAttrDefsByAttrId(CcCiClassInfo ciClassInfo, Long attrId) {
        List<CcCiAttrDef> attrDefs = ciClassInfo.getAttrDefs();
        if (CollectionUtils.isEmpty(attrDefs)) {
            return new ArrayList<>();
        }
        List<CcCiAttrDef> limitAttrDefs = new ArrayList<>();
        for (CcCiAttrDef attrDef : attrDefs) {
            if (attrDef.getProType() != AttrNameKeyEnum.EXTERNAL_ASSET.getType()
                    || !attrId.equals(attrDef.getId())) {
                continue;
            }
            limitAttrDefs.add(attrDef);
        }
        return limitAttrDefs;
    }

    private List<CcCiAttrDef> getLimitAttrDefs(CcCiClassInfo ciClassInfo, Long relateClassId) {
        List<CcCiAttrDef> attrDefs = ciClassInfo.getAttrDefs();
        if (CollectionUtils.isEmpty(attrDefs)) {
            return new ArrayList<>();
        }
        List<CcCiAttrDef> limitAttrDefs = new ArrayList<>();
        for (CcCiAttrDef attrDef : attrDefs) {
            if (attrDef.getProType() != AttrNameKeyEnum.EXTERNAL_ASSET.getType()
                    || !relateClassId.toString().equals(attrDef.getProDropSourceDef())) {
                continue;
            }
            limitAttrDefs.add(attrDef);
        }
        return limitAttrDefs;
    }
}
